#include "Kernel.h"
#include "Hal/IHardware.h"
#include "Memory/Heap.h"
#include "Drivers/Console.h"
#include "Drivers/Keyboard.h"
#include "Scheduler/Scheduler.h"
#include "Utils/String.h"
#include "Hal/x86/CPU.h"
#include "Hal/x86/IDT.h"
#include "Debugger.h"

using namespace x86;

CDebugger sDebugger;
CDebugger * Debugger = &sDebugger;

void CDebugger::Initialize( void )
{
}

bool CDebugger::__PutCharacter( char c, void * cookie )
{
    CDebugger * debugger = (Debugger *)cookie;

    if( debugger == NULL )
        return false;

	debugger->Write( c );
	return true;
}

void CDebugger::Write( const char * message, ... )
{
	Hardware->Lock();

	Args args;
	Args_Start( args, message );

	// initialize the parallel port
	IO_Out8( 0x037A, 0x02 | 0x04 | 0x08 | 0x20 );

	StringFormatArgs( message, args, &__PutCharacter, this );

	Args_End( args );

    Hardware->Unlock();
}

void CDebugger::Write( char c )
{
	// TODO: Parallel port debug output only seems to work in Bochs.

	// send via parallel port
	IO_Out8( 0x037A, IO_In8( 0x037A ) & ~0x05 );
	IO_Out8( 0x0378, (uint8)c );
	IO_Out8( 0x037A, IO_In8( 0x037A ) | 0x01 );

	// send via bochs debug port
	IO_Out8( 0xE9, (uint8)c );
}

void CDebugger::DumpMemory( void * memory, Size count )
{
	Write( "Dumping %d bytes at %08x\n", count, (Address)memory );

	for( uint8 * data = (uint8 *)memory; count > 0; data += 16 )
	{
		int i;
		for( i = 0; i < 16 && count > 0 ; i++ )
		{
			Write( "%02x ", data[i] );
			count--;
		}

		for( int j = i; j < 16; j++ )
		{
			Write( ' ' );
			Write( ' ' );
			Write( ' ' );
		}

		Write( ' ' );

		for( int j = 0; j < i; j++ )
		{
			if( data[j] < ' ' )
				Write( '.' );
			else
				Write( (char)data[j] );
		}

		Write( '\n' );
	}
}
